#ifndef _M_DB_H_
#define _M_DB_H_ 
#include<iostream>
#include<cassert>
#include<mutex>
#include"util.hpp"
using namespace std;

namespace im{
class UserTable{
     private:
       MYSQL *_mysql; 
       mutex _mutex;//互斥锁
     public:
       UserTable(const string &host,
           const string &user,
           const string &pass,
           const string &db,
           int port)//初始化数据库操作句柄
       {
         _mysql=MysqlUtil::mysql_create(host,user,pass,db,port);
         assert(NULL!=_mysql);
       }
       ~UserTable()//释放数据库操作句柄
       {
         MysqlUtil::mysql_destory(_mysql);
       }
       bool insert(const Json::Value &user)//新增用户
       {
 #define INSERT_USER "insert user values(null,'%s','%s',MD5('%s'),now());"
         char sql[4096]={0};
         snprintf(sql,4095,INSERT_USER,user["username"].asCString(),//将后面的数据存入sql中，存入大小为4095(若超过则截断)
                  user["nickname"].asCString(),
                  user["password"].asCString());
         return MysqlUtil::mysql_exec(_mysql,sql);//判断是否存入成功
       }
       bool check_login(const Json::Value &user)//登录验证
       {
 #define LOGIN_CHECK "select id from user where username='%s' and password=MD5('%s');"
         char sql[4096]={0};
         snprintf(sql,4095,LOGIN_CHECK,
                  user["username"].asCString(),
                  user["password"].asCString());
         MYSQL_RES *res;
        {
           unique_lock<mutex> lock(_mutex);//对互斥锁的自动管理,{}内自动加锁，生命周期结束后自动解锁
           bool ret=MysqlUtil::mysql_exec(_mysql,sql);
           if(ret==false)
           {
             return false;
           }
           res=mysql_store_result(_mysql);
           if(NULL==res)//获取信息失败，打印错误信息
           {
             cout<<"store result failed:"<<mysql_error(_mysql)<<endl;
             return false;
           }
        }
         int num_row=mysql_num_rows(res);//若我们输入多条相同用户的信息，验证时也会出错
         if(num_row!=1)
         {
          mysql_free_result(res);
          return false;
         }
         mysql_free_result(res);
         return true;
       }
bool update_password(const Json::Value &user)//修改用户密码
       {
 #define MOD_PASSWD_BY_NAME "update user set password=MD5('%s') where username='%s' and password=MD5('%s');"
         char sql[4096]={0};
         snprintf(sql,4095,MOD_PASSWD_BY_NAME,
                  user["new_password"].asCString(),
                  user["username"].asCString(),
                  user["old_password"].asCString());
         return MysqlUtil::mysql_exec(_mysql,sql);
       }
       bool update_nickname(const Json::Value &user)//昵称修改
       {
 #define MOD_NICKNAME_BY_NAME "update user set nickname='%s' where username='%s' and password=MD5('%s');"
         char sql[4096]={0};
         if(user["nickname"].asString().empty()||
             user["username"].asString().empty()||
             user["password"].asString().empty())
         {
           cout<<"update nickname data error!!"<<endl;
           return false;
         }
         snprintf(sql,4095,MOD_NICKNAME_BY_NAME,
                  user["nickname"].asCString(),                                                                      
                  user["username"].asCString(),
                  user["new_password"].asCString());
         return MysqlUtil::mysql_exec(_mysql,sql);
       }
       bool remove(int id)//删除用户
       {
 #define DELETE_USER "delete from user where id=%d;"
         char sql[4096]={0};
         snprintf(sql,4095,DELETE_USER,id);
         return MysqlUtil::mysql_exec(_mysql,sql);
       }
        bool select_by_id(int id,Json::Value *user)//通过id寻找用户，并将其储存在user中
       {
#define SELECT_USER_BY_ID "select username, nickname from user where id=%d"
        char sql[4096]={0};
         snprintf(sql,4095,SELECT_USER_BY_ID,id);
         MYSQL_RES *res;
        {
           unique_lock<mutex> lock(_mutex);//对互斥锁的自动管理,{}内自动加锁，生命周期结束后自动解锁
           bool ret=MysqlUtil::mysql_exec(_mysql,sql);
           if(ret==false)
           {
             return false;
           }
           res=mysql_store_result(_mysql);
           if(NULL==res)//获取信息失败，打印错误信息
           {
             cout<<"store result failed:"<<mysql_error(_mysql)<<endl;
             return false;
           }
        }
         int num_row=mysql_num_rows(res);//通过结果集获取一条数据
         if(num_row!=1)//获取失败
         {
           cout<<"query result error!!"<<endl;
           return false;
         }
         MYSQL_ROW row=mysql_fetch_row(res);//遍历结果集
         (*user)["id"]=id;
         (*user)["username"]=row[0];
         (*user)["nickname"]=row[1];
         mysql_free_result(res);//释放结果集
         return true;
       }
 bool select_by_name(const string &name,Json::Value *user)//通过名称寻找用户
       {
#define SELECT_USER_BY_NAME "select id, nickname from user where username='%s'"
         char sql[4096]={0};
         snprintf(sql,4095,SELECT_USER_BY_NAME,name.c_str());
         MYSQL_RES *res;
         {
           unique_lock<mutex> lock(_mutex);
           bool ret=MysqlUtil::mysql_exec(_mysql,sql);
           if(ret!=1)
           {
             return false;
           }
           res=mysql_store_result(_mysql);
           if(NULL==res)
           {
             cout<<"store result failed:"<<mysql_error(_mysql)<<endl;
             return false;
           }
         }
         int num_row=mysql_num_rows(res);
         if(num_row!=1)
         {
           cout<<"query result error!!"<<endl;
           return false;
         }
         MYSQL_ROW row=mysql_fetch_row(res);
         (*user)["id"]=stoi(row[0]);
         (*user)["username"]=name;
         (*user)["nickname"]=row[1];
         mysql_free_result(res);
         return true;
       }
};
 class MsgTable{                                                                                                                                                                 
   private:
       MYSQL *_mysql;
       mutex _mutex;
     public:
       MsgTable(const string &host,
           const string &user,
           const string &pass,
           const string &db,
           int port)
       {
         _mysql=MysqlUtil::mysql_create(host,user,pass,db,port);
         assert(NULL!=_mysql);
       }
       ~MsgTable()
       {
         MysqlUtil::mysql_destory(_mysql);
       }
       bool insert(const Json::Value &msg)
       {
 #define INSERT_MSG "insert message values(null,%d,'%s',now());"
         char sql[4096]={0};
         snprintf(sql,4095,INSERT_MSG,
                  msg["uid"].asInt(),
                  msg["msg"].asCString());
         return MysqlUtil::mysql_exec(_mysql,sql);
       }
       bool select_part(int sec, Json::Value *msg)
       {
#define SELECT_PART_MSG "select id,uid,msg,ctime from message where timestampdiff(second,ctime,now())<%d"
          char sql[4096]={0};
          snprintf(sql,4095,SELECT_PART_MSG,sec);
          MYSQL_RES *res;
          {
            unique_lock<mutex> lock(_mutex);
            bool ret=MysqlUtil::mysql_exec(_mysql,sql);
            if(ret==false)
            {
              return false;
            }
            res=mysql_store_result(_mysql);
            if(NULL==res)
            {
              cout<<"store result failed:"<<mysql_error(_mysql)<<endl;
              return false;
            }
          }
          int num_row=mysql_num_rows(res);
          for(int i=0;i<num_row;i++)
          {
            MYSQL_ROW row=mysql_fetch_row(res);
            Json::Value m;
            m["id"]=stoi(row[0]);
            m["uid"]=stoi(row[1]);
            m["msg"]=row[2];
            m["ctime"]=row[3];
            msg->append(m);
          }
          mysql_free_result(res);
          return true;
       }
};
}
#endif 
